package tcp.socket.thread;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import tcp.socket.Server;
import thread.MyThreadPool;

/**
 * 最简单的多线程服务端，但是每次都需要创建线程，效率低下
 * @author Han
 */
public class ThreadServerWithClose {
	private static final int PORT = 9999;
	private ServerSocket serverSocket;
	private ExecutorService threadPool;
	
	private static final int SHUTDOWN_PORT = 9001;
	private ServerSocket serverSocketForShutdown;
	private boolean isShutdown = false;
	
	private Thread shutdownThread = new Thread(){
		public void start(){
			this.setDaemon(true);
			super.start();
		}
		public void run() {
			while(!isShutdown){
				Socket socketForShutdown = null;
				try {
					socketForShutdown = serverSocketForShutdown.accept();
					BufferedReader reader = new BufferedReader(new InputStreamReader(socketForShutdown.getInputStream()));
					String commond = reader.readLine();
					if(commond.equals("shutdown")){
						long beginTime = System.currentTimeMillis();
						socketForShutdown.getOutputStream().write("服务器正在关闭...\r\n".getBytes());
						isShutdown = true;
						//关闭线程池，不再接收请求
						threadPool.shutdown();
						//等待关闭线程池，每次等到的时间为30秒
						while(!threadPool.isTerminated()){
							threadPool.awaitTermination(30, TimeUnit.SECONDS);
						}
						//所有任务完成后执行关闭操作
						serverSocket.close();
						
						long endTime = System.currentTimeMillis();
						socketForShutdown.getOutputStream().write(("服务器已关闭，用时"+(endTime-beginTime)+"毫秒...\r\n").getBytes());
						socketForShutdown.close();
						serverSocketForShutdown.close();
					}else{
						socketForShutdown.getOutputStream().write(("错误的命令\r\n").getBytes());
						socketForShutdown.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
	};
	
	public ThreadServerWithClose() throws IOException{
		//没有指定长度的情况下，默认只能50个连接
		//同时可以设置绑定的ip地址，从而只允许局域网的连接
		//无参构造要先设置参数，再绑定端口。绑定端口后，参数设置将无效。
		serverSocket = new ServerSocket(PORT);
		//设置等待客户连接的超时时间为60秒
		serverSocket.setSoTimeout(60000);
		threadPool = Executors.newFixedThreadPool(20);
		serverSocketForShutdown = new ServerSocket(SHUTDOWN_PORT);
		shutdownThread.start();
	}
	
	
	public void service(){
		while(!isShutdown){
			Socket socket = null;
			try {
				socket = serverSocket.accept();
				//交给线程池去做
//				Thread thread = new Thread(new Handler(socket));
//				thread.start();
				threadPool.execute(new Handler(socket));
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	class Handler implements Runnable{
		private Socket socket;
		public Handler(Socket socket){
			this.socket = socket;
		}
		
		private PrintWriter getWriter(Socket socket) throws IOException{
			OutputStream os = socket.getOutputStream();
			return new PrintWriter(os, true);
		}
		
		private BufferedReader getReader(Socket socket) throws IOException{
			InputStream is = socket.getInputStream();
			return new BufferedReader(new InputStreamReader(is));
		}
		
		@Override
		public void run() {
			try {
				BufferedReader br = getReader(socket);
				PrintWriter pw = getWriter(socket);
				String msg = null;
				while((msg = br.readLine()) != null){
					System.out.println("recieve:"+msg);
					pw.println(System.currentTimeMillis());
					if(msg.equals("bye")){
						break;
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				if(socket != null){
					try {
						socket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	//
	public static void main(String[] args) {
		try {
			ThreadServerWithClose server = new ThreadServerWithClose();
			server.service();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
